package com.vcc.web.controller;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.mybatisflex.core.paginate.Page;
import com.vcc.channel.base.model.request.CreateCardHolderDto;
import com.vcc.channel.base.model.request.UpdateCardHolderDto;
import com.vcc.channel.service.service.PhotonService;
import com.vcc.core.annotations.CurrentROStatus;
import com.vcc.core.annotations.KycReject;
import com.vcc.core.annotations.ROReject;
import com.vcc.core.annotations.RestPack;
import com.vcc.core.exception.NotFoundException;
import com.vcc.core.exception.ProgramException;
import com.vcc.core.model.file.cardholder.CardholderFilePojo;
import com.vcc.core.util.CardholderUtil;
import com.vcc.core.util.FileUtil;
import com.vcc.core.util.RegexUtil;
import com.vcc.data.entity.Cardholder;
import com.vcc.data.entity.Role;
import com.vcc.data.entity.User;
import com.vcc.service.client.dto.cardholder.ClientCardholderCreateRequest;
import com.vcc.service.client.dto.cardholder.UpdateCardholderDto;
import com.vcc.service.client.dto.cardholder.UpdateCardholderStatusDto;
import com.vcc.service.client.vo.cardholder.CardholderVo;
import com.vcc.service.service.CardholderService;
import com.vcc.service.service.UserService;
import com.vcc.web.core.util.UserUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping("cardholder")
public class CardholderController {

    @Autowired
    private CardholderService cardholderService;
    @Autowired
    private UserService userService;
    @Resource
    private PhotonService photonService;

    @RestPack
    @GetMapping("paging")
    @SaCheckPermission("card:cardholder:view")
    public Page<CardholderVo> paging(
            Integer pageNumber,
            Integer pageSize,
            Long targetUserId,
            Long id,
            Integer status,
            String startDate,
            String endDate,
            String fistName) {
        User user = UserUtil.get();
        Long parentId = user.getParentId();
        Role role = UserUtil.getRole();
        return cardholderService.paging(
                role.getHasAllData() && parentId != null && parentId != 0 ? parentId : user.getId(),
                role,
                targetUserId,
                Page.of(
                        pageNumber != null ? pageNumber : 1,
                        pageSize != null ? pageSize : 20
                ),
                id,
                fistName,
                status,
                startDate,
                endDate);
    }

    @ROReject
    @KycReject
    @RestPack
    @SaCheckPermission("card:cardholder:search")
    @GetMapping("listByUserId")
    public List<CardholderVo> listByUserId(Integer status) {
        List<Cardholder> cardholders = cardholderService.listByUserId(UserUtil.getId(), RegexUtil.checkObjectIsNotNull(status) ? status : 0);
        return cardholders.stream().map(CardholderVo::new).collect(Collectors.toList());
    }

    @ROReject
    @KycReject
    @RestPack
    @SaCheckPermission("card:cardholder:edit")
    @PostMapping("updateStatus")
    public Boolean updateStatus(@RequestBody UpdateCardholderStatusDto updateCardholderStatusDto) {
        return cardholderService.updateStatus(updateCardholderStatusDto);
    }

    @ROReject
    @KycReject
    @RestPack
    @SaCheckPermission("card:cardholder:create")
    @PostMapping("createCardholder")
    public Boolean createCardholder(@RequestBody ClientCardholderCreateRequest clientCardholderCreateRequest) {
        Long userId = UserUtil.getId();
        checkValueIsNull(clientCardholderCreateRequest.getFirstName(), "姓不能为空");
        //hutool判断firstname中是不是只有字母
        if (!Validator.isWord(clientCardholderCreateRequest.getFirstName())) {
            throw new ProgramException("姓只能包含字母");
        }
        checkValueIsNull(clientCardholderCreateRequest.getLastName(), "名不能为空");
        //hutool判断lastname中是不是只有字母
        if (!Validator.isWord(clientCardholderCreateRequest.getLastName())) {
            throw new ProgramException("名只能包含字母");
        }
        checkValueIsNull(clientCardholderCreateRequest.getPhone(), "手机号不能为空");
        checkValueIsNull(clientCardholderCreateRequest.getCountry(), "国家不能为空");
        if (!Validator.isWord(clientCardholderCreateRequest.getLastName())) {
            throw new ProgramException("名只能包含字母");
        }
        if (clientCardholderCreateRequest.getCountry().length() != 2) {
            throw new ProgramException("国家代码必须为2位");
        }
        checkValueIsNull(clientCardholderCreateRequest.getProvince(), "省份不能为空");
        checkValueIsNull(clientCardholderCreateRequest.getCity(), "城市不能为空");
//        checkValueIsNull(createCardholderDto.getArea(), "区域不能为空");
        checkValueIsNull(clientCardholderCreateRequest.getPostCode(), "邮编不能为空");
        checkValueIsNull(clientCardholderCreateRequest.getAddress(), "地址不能为空");
        checkValueIsNull(clientCardholderCreateRequest.getBirthday(), "生日不能为空");
        checkValueIsNull(clientCardholderCreateRequest.getMobilePrefix(), "手机号前缀不能为空");
        //生日必须大于18岁yyyy-MM-dd
        DateTime birthday = DateUtil.parse(clientCardholderCreateRequest.getBirthday(), DatePattern.NORM_DATE_PATTERN);
        int birthdayYear = DateUtil.ageOfNow(birthday);
        if (birthdayYear < 18) {
            throw new ProgramException("持卡人必须年满18岁");
        }
        if (cardholderService.existsFirstNameByUserId(clientCardholderCreateRequest.getFirstName(), userId)) {
            throw new NotFoundException("持卡人名字已存在");
        }
        if (cardholderService.existsEmailByUserId(clientCardholderCreateRequest.getEmail(), userId)) {
            throw new NotFoundException("持卡人邮箱已存在");
        }
        if (cardholderService.existsPhoneByUserId(clientCardholderCreateRequest.getPhone(), userId)) {
            throw new NotFoundException("持卡人电话已存在");
        }
        clientCardholderCreateRequest.setEmail(CardholderUtil.createRandomEmail());
        String cardHolder = photonService.createCardHolder(
                CreateCardHolderDto.builder()
                        .firstName(clientCardholderCreateRequest.getFirstName())
                        .lastName(clientCardholderCreateRequest.getLastName())
                        .email(clientCardholderCreateRequest.getEmail())
                        .mobile(clientCardholderCreateRequest.getPhone())
                        .country(clientCardholderCreateRequest.getCountry())
                        .state(clientCardholderCreateRequest.getProvince())
                        .city(clientCardholderCreateRequest.getCity())
                        .area(clientCardholderCreateRequest.getArea())
                        .zipCode(clientCardholderCreateRequest.getPostCode())
                        .address(clientCardholderCreateRequest.getAddress())
                        .mobilePrefix(clientCardholderCreateRequest.getMobilePrefix())
                        .birthDay(clientCardholderCreateRequest.getBirthday())
                        .build()
        );
        HashMap<String, Object> info = new HashMap<>();
        ArrayList<HashMap<String, Object>> accounts = new ArrayList<>();
        HashMap<String, Object> account = new HashMap<>();
        account.put("account", "V1");
        account.put("value", cardHolder);
        accounts.add(account);
        info.put("PhotonPay", accounts);
        clientCardholderCreateRequest.setCardholderInfo(JSONUtil.toJsonStr(info));
        cardholderService.createCardholder(userId, clientCardholderCreateRequest);
        return true;
    }

    @ROReject
    @KycReject
    @RestPack
    @PostMapping("updateCardholder")
    @SaCheckPermission("card:cardholder:edit")
    @SaCheckLogin
    public Boolean updateCardholder(@RequestBody @Validated UpdateCardholderDto updateCardholderDto) {
        checkValueIsNull(updateCardholderDto.getFirstName(), "姓不能为空");
        //hutool判断firstname中是不是只有字母
        if (!Validator.isWord(updateCardholderDto.getFirstName())) {
            throw new ProgramException("姓只能包含字母");
        }
        checkValueIsNull(updateCardholderDto.getLastName(), "名不能为空");
        //hutool判断lastname中是不是只有字母
        if (!Validator.isWord(updateCardholderDto.getLastName())) {
            throw new ProgramException("名只能包含字母");
        }
        checkValueIsNull(updateCardholderDto.getPhone(), "手机号不能为空");
        checkValueIsNull(updateCardholderDto.getCountry(), "国家不能为空");
        if (!Validator.isWord(updateCardholderDto.getCountry())) {
            throw new ProgramException("国家只能包含字母");
        }
        if (updateCardholderDto.getCountry().length() != 2) {
            throw new ProgramException("国家代码必须为2位");
        }
        checkValueIsNull(updateCardholderDto.getProvince(), "省份不能为空");
        checkValueIsNull(updateCardholderDto.getCity(), "城市不能为空");
//        checkValueIsNull(updateCardholderDto.getArea(), "区域不能为空");
        checkValueIsNull(updateCardholderDto.getPostCode(), "邮编不能为空");
        checkValueIsNull(updateCardholderDto.getAddress(), "地址不能为空");
        Cardholder cardholder = cardholderService.getById(updateCardholderDto.getId());
        if (cardholder == null) {
            throw new NotFoundException("持卡人信息不存在");
        }
        baseVerifyUserCardUser(UserUtil.getRole(), UserUtil.getId(), cardholder);
        JSONObject cardholderInfo = JSONObject.parseObject(cardholder.getCardholderInfo());
        cardholderInfo.getJSONArray("PhotonPay").forEach(item -> {
            JSONObject account = (JSONObject) item;
            photonService.updateCardHolder(
                    UpdateCardHolderDto.builder()
                            .firstName(updateCardholderDto.getFirstName())
                            .lastName(updateCardholderDto.getLastName())
                            .email(cardholder.getEmail()) // 不接受外部邮箱填写
                            .mobile(updateCardholderDto.getPhone())
                            .country(updateCardholderDto.getCountry())
                            .state(updateCardholderDto.getProvince())
                            .city(updateCardholderDto.getCity())
                            .area(updateCardholderDto.getArea())
                            .zipCode(updateCardholderDto.getPostCode())
                            .address(updateCardholderDto.getAddress())
                            .cardholderId(account.getString("value"))
                            .mobilePrefix(updateCardholderDto.getMobilePrefix())
                            .birthDay(updateCardholderDto.getBirthday())
                            .build()
            );
        });
        return cardholderService.updateCardholder(UserUtil.getId(), updateCardholderDto);
    }


    /**
     * 校验卡所属
     *
     * @param role   操作用户的权限
     * @param userId 操作用户ID
     */
    private void baseVerifyUserCardUser(Role role, Long userId, Cardholder cardholder) {
        if (role.getHasAllData()) {
            //获取卡片所属经销商
            // dealerId 是 0 则是主账户，非0 则是子账户
            Long dealerId = userService.getParentIdById(userId);
            //userCardDealerId == 0 则是主账户的卡，非0 则是子账户的卡
            Long userCardDealerId = userService.getParentIdById(cardholder.getUserId());
            if (dealerId != 0L) {
                // 如果卡不是主账户的也不是主账户名下用户的责非法操作
                if (
                        !cardholder.getUserId().equals(userId) &&
                                !cardholder.getUserId().equals(dealerId) &&
                                !userCardDealerId.equals(dealerId)
                ) {
                    throw new ProgramException("非法操作");
                }
            } else {
                //主账户在操作
                //主账户时 判断卡的所属主账户是否等于操作用户和卡所属用户是否等于操作用户
                if (!userCardDealerId.equals(userId) && !cardholder.getUserId().equals(userId)) {
                    throw new ProgramException("非法操作");
                }
            }
        } else {
            if (!userId.equals(cardholder.getUserId())) {
                throw new ProgramException("非法操作");
            }
        }
    }

    @RestPack
    @GetMapping("derive")
    @SaCheckPermission("card:cardholder:derive")
    public void derive(
            @CurrentROStatus Boolean roStatus,
            Long targetUserId,
            Long id,
            String fistName,
            Integer status,
            String startDate,
            String endDate,
            HttpServletResponse response
    ) {
        User user = UserUtil.get();
        Long parentId = user.getParentId();
        Role role = UserUtil.getRole();
        SXSSFWorkbook sxssfWorkbook = FileUtil.createCardholderTitle(1000);
        Page<CardholderVo> paging;
        Long pages = 1L;
        do {
            paging = new Page<>(pages++, 20);
            Page<CardholderVo> page = cardholderService.paging(
                    role.getHasAllData() && parentId != 0 ? parentId : user.getId(),
                    role,
                    targetUserId,
                    paging, id, fistName, status, startDate, endDate);
            List<CardholderFilePojo> map = page.getRecords().stream().map(it -> new CardholderFilePojo(
                    it.getId(),
                    user.getAccount(),
                    it.getFirstName(),
                    it.getLastName(),
                    it.getCountry(),
                    it.getProvince(),
                    it.getCity(),
                    it.getArea(),
                    it.getPostCode(),
                    it.getAddress(),
                    it.getPhone(),
                    it.getEmail(),
                    it.getRemark()
            )).collect(Collectors.toList());
            FileUtil.deriveCardholderData(sxssfWorkbook, map, page.getPageNumber(), page.getPageSize());
        } while (!(pages).equals(paging.getTotalPage() + 1));
        String fileName = System.currentTimeMillis() + "持卡人信息.xlsx";

        FileUtil.downXlsxFile(response, sxssfWorkbook, fileName);

    }


    private void checkValueIsNull(String value, String message) {
        if (RegexUtil.checkStringIsNull(value)) {
            throw new ProgramException(message);
        }
    }


}
